package com.sl.proxy.client.handler;

import com.sl.proxy.client.config.ProxyClientConfig;
import com.sl.proxy.client.core.ProxyChannelBorrowListener;
import com.sl.proxy.client.util.ProxyUtil;
import com.sl.proxy.core.Constants;
import com.sl.proxy.core.ProxyDataTypeEnum;
import com.sl.proxy.core.ProxyMessage;
import com.sl.proxy.core.ProxyMessageHandler;
import com.sl.proxy.core.dispatcher.Match;
import lombok.RequiredArgsConstructor;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import org.springframework.aop.framework.ProxyConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 * 连接信息处理器
 *
 * @author: aoshiguchen
 * @date: 2022/6/16
 */
@Match(type = Constants.ProxyDataTypeName.CONNECT)
@RequiredArgsConstructor
public class ProxyMessageConnectHandler implements ProxyClientMessageHandler {
    @Autowired
    @Qualifier("tcpProxyTunnelBootstrap")
    private Bootstrap tcpProxyTunnelBootstrap;
    @Autowired
    @Qualifier("realServerBootstrap")
    private Bootstrap realServerBootstrap;
    private final ProxyClientConfig proxyConfig;

    @Override
    public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
        final Channel cmdChannel = ctx.channel();
        final String visitorId = proxyMessage.getInfo();
        String[] serverInfo = new String(proxyMessage.getData()).split(":");
        String ip = serverInfo[0];
        int port = Integer.parseInt(serverInfo[1]);
        // 连接真实的、被代理的服务
        realServerBootstrap.connect(ip, port).addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture future) throws Exception {

                // 连接后端服务器成功
                if (future.isSuccess()) {
                    final Channel realServerChannel = future.channel();

                    realServerChannel.config().setOption(ChannelOption.AUTO_READ, false);

                    // 获取连接
                    ProxyUtil.borrowTcpProxyChanel(tcpProxyTunnelBootstrap, new ProxyChannelBorrowListener() {

                        @Override
                        public void success(Channel channel) {
                            // 连接绑定
                            channel.attr(Constants.NEXT_CHANNEL).set(realServerChannel);
                            realServerChannel.attr(Constants.NEXT_CHANNEL).set(channel);

                            // 远程绑定
                            channel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId + "@" + proxyConfig.getTunnel().getLicenseKey()));

                            realServerChannel.config().setOption(ChannelOption.AUTO_READ, true);
                            ProxyUtil.addRealServerChannel(visitorId, realServerChannel);
                            ProxyUtil.setRealServerChannelVisitorId(realServerChannel, visitorId);
                        }

                        @Override
                        public void error(Throwable cause) {
                            ProxyMessage proxyMessage = new ProxyMessage();
                            proxyMessage.setType(ProxyMessage.TYPE_DISCONNECT);
                            proxyMessage.setInfo(visitorId);
                            cmdChannel.writeAndFlush(proxyMessage);
                        }
                    });

                } else {
                    cmdChannel.writeAndFlush(ProxyMessage.buildDisconnectMessage(visitorId));
                }
            }
        });
    }

    @Override
    public String name() {
        return ProxyDataTypeEnum.CONNECT.getDesc();
    }
}
